package model

import (
	"errors"
	"github.com/imroc/req"
	"math"
	"src/config"
	"src/util/context"
	"src/util/gps"
	"src/util/time"
	"strconv"
)

type BusMessage struct {
	Lat          float64   `json:"lat" bson:"lat"`                     //原纬度
	Lon          float64   `json:"lon" bson:"lon"`                     //原经度
	Lat1         float64   `json:"lat_1" bson:"lat_1"`                 //规约纬度
	Lon1         float64   `json:"lon_1" bson:"lon_1"`                 //规约经度
	Distance     float64   `json:"distance" bson:"distance"`           //规约距离
	PreStationid int       `json:"pre_stationid" bson:"pre_stationid"` //上一站id
	PlateNumber  string    `json:"plateNumber"`                        //编号
	Stations     []Station `json:"stations" bson:"stations"`           //站数组
	Percent      float64   `json:"percent" bson:"percent"`             //占总路程百分比
	Direction    int       `json:"direction"`                          //方向:2,3表示到站（起始站，终点站），0表示正序，1表示反序,5表示未定
	BusDriveDir  int       `json:"bus_drive_dir"`                      //行驶方向 0为北 1为东，2为南，3为西
}

type Station struct {
	PreStaDistance float64 `json:"pre_sta_distance"` //上一站距离
	LasStaDistance float64 `json:"las_sta_distance"` //下一站距离
	Name           string  `json:"name"`             //站名
	Flag           int     `json:"flag"`             //为1时为校车站点，为0时表示仅为路线上一个节点
	StationNum     float64 `json:"station_num"`      //和校车之间的站数,包括当前站
}

type Bus struct {
	PlateNumber       string    `json:"plateNumber"`
	Gps               [2]string `json:"gps"`
	Status            float64   `json:"status"` //0.0表示正在运行，1.0表示已停止，2.0表示已关闭
	DriverName        string    `json:"driverName"`
	DriverPhoneNumber string    `json:"driverPhoneNumber"`
	LineNumber        int       `json:"lineNumber"` //所属线路
	Sn                string    `json:"sn"`
}

type Buses struct {
	Code         int    `json:"code"`
	ErrorMessage string `json:"errorMessage"`
	Data         []Bus  `json:"data"`
}

//4个值相加：8表示在终点站，有2的话看和两个终点站距离,0-1正序，2沿袭上一个状态，3-4反序

var BusesMessage [config.BusNum]BusMessage
var BusesFlag [config.BusNum]bool
var BusesEXPTime [config.BusNum]int64

//更新所有校车状态信息
func SetAllBusState() {
	//RedisDBCntlr := NewRedisDBCntlr()
	url := config.GPSUrl
	param := req.Param{}
	var data Buses
	err := context.BindGetJSONData(url, param, &data)
	if err != nil {
		return
	}
	//JudgeRoute(data) //先进行路线判断
	var rouid int
	var busmessage BusMessage
	for i := 0; i < len(data.Data); i++ {
		rouid = config.Rou.BusRoute[data.Data[i].PlateNumber]      //路线下标
		id := config.Busmessages.BusToId[data.Data[i].PlateNumber] //校车之前信息记录的下标
		Lon, err := strconv.ParseFloat(data.Data[i].Gps[0], 64)    //WGS经度
		if err != nil {
			continue
		}
		Lat, err := strconv.ParseFloat(data.Data[i].Gps[1], 64) //WGS维度
		if err != nil {
			continue
		}
		UpdateBusDis(id, Lat, Lon) //更新  判断是否移动信息 队列

		flag := 0
		for _, j := range config.Busmessages.BusMessage[id].BusMovQueue {
			if j >= config.IsMove {
				flag = 1
				break
			}
		} //判断是否停车 flag为1表示2min内 移动过
		if flag == 1 && rouid >= 0 && rouid < len(config.Rou.Routes) { //在运行且有路线
			busmessage, err = UpdateBus(data.Data[i], config.Rou.Routes[rouid], id) //获取更新内容
			if err != nil {                                                         //若更新有错，不进行任何操作，等待过期
				continue
			}
			busmessage.Lon, busmessage.Lat = gps.WGS84toGCJ02(busmessage.Lon, busmessage.Lat)     //WGS经纬度转GCJ
			busmessage.Lon1, busmessage.Lat1 = gps.WGS84toGCJ02(busmessage.Lon1, busmessage.Lat1) //WGS经纬度转GCJ

			//d, _ := json.MarshalIndent(busmessage, "", "  ")
			//redisnewid := bson.NewObjectId().Hex()
			//_, err = RedisDBCntlr.SETEX(redisnewid, 15, string(d)) //15s
			//if err != nil {
			//	println(err.Error())
			//	continue
			//}
			//_, err = RedisDBCntlr.SETEX(data.Data[i].PlateNumber, 15, redisnewid) //15s
			//if err != nil {
			//	println(err.Error())
			//	continue
			//}

			BusesMessage[id] = busmessage                                           //更新校车信息
			BusesEXPTime[id] = time.GetSecondTimestampByN(config.BusMessageExpTime) //设置过期时间为60s后
			BusesFlag[id] = true                                                    //标记为在运行
		} else { //2min内未移动 判断为离线
			//_, _ = RedisDBCntlr.DEL(data.Data[i].PlateNumber)
			initBusMessage(id)
			BusesFlag[id] = false //标记为离线
		}
		BusesMessage[id].BusDriveDir = config.Busmessages.BusMessage[id].BusDriveDir
	}
	//RedisDBCntlr.Close()
}

//初始化信息
func initBusMessage(id int) {
	if config.Busmessages.BusMessage[id].BusDirection[0] == 2 {
		config.Busmessages.BusMessage[id].Result = 2                        //上次判断的移动方向
		config.Busmessages.BusMessage[id].BusDirection = [4]int{2, 2, 2, 2} //四次真实移动方向记录
	} else if config.Busmessages.BusMessage[id].BusDirection[0] == 3 {
		config.Busmessages.BusMessage[id].Result = 3                        //上次判断的移动方向
		config.Busmessages.BusMessage[id].BusDirection = [4]int{3, 3, 3, 3} //四次真实移动方向记录
	} else {
		config.Busmessages.BusMessage[id].Result = 5                        //上次判断的移动方向
		config.Busmessages.BusMessage[id].BusDirection = [4]int{5, 5, 5, 5} //四次真实移动方向记录
	}
}

//更新  判断是否移动  的队列
func UpdateBusDis(ID int, Lat, Lon float64) {
	var busmes *config.BusMessage
	busmes = &config.Busmessages.BusMessage[ID] //校车之前的信息
	if busmes.PreGPS_WGS84[0] == 0.0 {
		busmes.PreGPS_WGS84 = [2]float64{Lat, Lon}
		busmes.PreGPS_GCJ02[1], busmes.PreGPS_GCJ02[0] = gps.WGS84toGCJ02(Lon, Lat)
	} else {
		busmes.BusMovQueue[busmes.BusMovQueuepr] = gps.GetDistance(Lat, Lon, busmes.PreGPS_WGS84[0], busmes.PreGPS_WGS84[1])
		busmes.BusMovQueuepr = (busmes.BusMovQueuepr + 1) % config.QUEUELENG
		if math.Abs(Lat-busmes.PreGPS_WGS84[0])*0.8615405652 > math.Abs(Lon-busmes.PreGPS_WGS84[1]) {
			if Lat > busmes.PreGPS_WGS84[0] {
				busmes.BusDriveDir = 0 //0为北
			} else {
				busmes.BusDriveDir = 2 //2为南
			}
		} else if math.Abs(Lat-busmes.PreGPS_WGS84[0])*0.8615405652 < math.Abs(Lon-busmes.PreGPS_WGS84[1]) {
			if Lon > busmes.PreGPS_WGS84[1] {
				busmes.BusDriveDir = 1 // 1为东
			} else {
				busmes.BusDriveDir = 3 //3为西
			}
		} else {
			if Lon-busmes.PreGPS_WGS84[1] != 0 {
				busmes.BusDriveDir = (busmes.BusDriveDir + 1) % 2
			}
		}
		busmes.PreGPS_WGS84[0], busmes.PreGPS_WGS84[1] = Lat, Lon
		busmes.PreGPS_GCJ02[1], busmes.PreGPS_GCJ02[0] = gps.WGS84toGCJ02(Lon, Lat)
	}
}

//计算校车更新内容
func UpdateBus(bus Bus, route config.Route, ID int) (BusMessage, error) {

	var busmes *config.BusMessage
	busmes = &config.Busmessages.BusMessage[ID] //校车之前信息的记录
	newbus := BusMessage{}                      //所需要的更细信息变量
	var err error

	//初始化结构体
	newbus.Lon, err = strconv.ParseFloat(bus.Gps[0], 64) //经度
	if err != nil {
		return BusMessage{}, err
	}
	newbus.Lat, err = strconv.ParseFloat(bus.Gps[1], 64) //纬度
	if err != nil {
		return BusMessage{}, err
	}

	newbus.PlateNumber = bus.PlateNumber //编号

	//求规约点与规约距离、规约路线段
	newbus.PreStationid, newbus.Lat1, newbus.Lon1, newbus.Distance = findStation(newbus.Lat, newbus.Lon, route, busmes.Result)
	// 若规约距离过大，尝试对相反路线进行规约
	if newbus.Distance > config.BusMinVertDis {
		i := 0
		if busmes.Result == 0 || busmes.Result == 2 || busmes.Result == 5 {
			i = 1
		} else {
			i = 0
		}
		newbus.PreStationid, newbus.Lat1, newbus.Lon1, newbus.Distance = findStation(newbus.Lat, newbus.Lon, route, i) //尝试反向路线
		//规约距离过大，认为其偏离路线，不在运行
		if newbus.Distance > config.BusMinVertDis {
			return BusMessage{}, errors.New("不在规定路线上" + strconv.FormatFloat(newbus.Distance, 'f', 10, 64))
		}
		//认为在相反路线，更改方向
		busmes.Result = i
		busmes.BusDirection = [4]int{i, i, i, i}
	}

	//初始化节点
	tem := Station{}
	var newbus1 []config.Station
	if busmes.Result == 0 || busmes.Result == 2 || busmes.Result == 5 {
		newbus1 = route.Points
		for _, j := range route.Points {
			tem.PreStaDistance = j.PreStaDistance
			tem.LasStaDistance = j.LasStaDistance
			tem.Flag = j.Flag
			tem.Name = j.Name
			newbus.Stations = append(newbus.Stations, tem)
		}
	} else {
		newbus1 = route.OppositePoints
		for _, j := range route.OppositePoints {
			tem.PreStaDistance = j.PreStaDistance
			tem.LasStaDistance = j.LasStaDistance
			tem.Flag = j.Flag
			tem.Name = j.Name
			newbus.Stations = append(newbus.Stations, tem)
		}
	}

	//stanum1,stanum2 : 车的前面站数，后面站数  dis1,dis2:和前面一战、后面一站站距离
	stanum1, stanum2, dis1, dis2 := 0.0, 0.0, 0.0, 0.0
	flag := 0
	//更新每个节点信息
	//往后更新
	i := newbus.PreStationid + 1
	newbus.Stations[i].PreStaDistance = gps.GetDistance(newbus.Lat1, newbus.Lon1, newbus1[i].WGS84Lat, newbus1[i].WGS84lon)
	if newbus.Stations[i].Flag == 1 {
		stanum2 += 1
		dis2 = newbus.Stations[i].PreStaDistance
		flag = 1
	}
	newbus.Stations[i].StationNum = stanum2
	i++
	for ; i < len(newbus.Stations); i++ {
		newbus.Stations[i].PreStaDistance = newbus.Stations[i-1].PreStaDistance + newbus.Stations[i-1].LasStaDistance
		if newbus.Stations[i].Flag == 1 {
			stanum2 += 1
			if flag == 0 {
				dis2 = newbus.Stations[i].PreStaDistance
				flag = 1
			}
		}
		newbus.Stations[i].StationNum = stanum2
	}
	//往前更新
	flag = 0
	i = newbus.PreStationid
	newbus.Stations[i].PreStaDistance = gps.GetDistance(newbus.Lat1, newbus.Lon1, newbus1[i].WGS84Lat, newbus1[i].WGS84lon)
	if newbus.Stations[i].Flag == 1 {
		stanum1 += 1
		dis1 = newbus.Stations[i].PreStaDistance
		flag = 1
	}
	newbus.Stations[i].StationNum = stanum1
	i--
	for ; i >= 0; i-- {
		newbus.Stations[i].PreStaDistance = newbus.Stations[i+1].PreStaDistance + newbus.Stations[i].LasStaDistance
		if newbus.Stations[i].Flag == 1 {
			stanum1 += 1
			if flag == 0 {
				dis1 = newbus.Stations[i].PreStaDistance
				flag = 1
			}
		}
		newbus.Stations[i].StationNum = stanum1
	}
	//更新路程百分比
	newbus.Percent = (float64(stanum1)-1)/(float64(stanum1)+stanum2-1) + (float64(dis1)/(dis1+dis2))/(float64(stanum1)+stanum2-1)
	newbus.Percent *= 100

	//更新方向
	if busmes.BusDirection[0] == 5 && busmes.BusMovQueue[busmes.BusMovQueuepr] == 0 { //如果方向未定，说明是初始化的数据
		newbus.Direction = 5
	} else { //不是初始化的数据
		if (newbus.Stations[0].PreStaDistance <= config.BusMinStationDis && (busmes.Result == 0 || busmes.Result == 2 || busmes.Result == 5)) || (newbus.Stations[len(newbus.Stations)-1].PreStaDistance <= config.BusMinStationDis && (busmes.Result == 1 || busmes.Result == 3)) {
			//在出发站
			newbus.Direction = 2
			busmes.BusDirection = [4]int{2, 2, 2, 2}
		} else if (newbus.Stations[len(newbus.Stations)-1].PreStaDistance <= config.BusMinStationDis && (busmes.Result == 0 || busmes.Result == 2 || busmes.Result == 5)) || (newbus.Stations[0].PreStaDistance <= config.BusMinStationDis && (busmes.Result == 1 || busmes.Result == 3)) {
			//在终点站
			newbus.Direction = 3
			busmes.BusDirection = [4]int{3, 3, 3, 3}
		} else {
			//在路线上

			//初步判断方向（观察距出发站距离的变化）
			if busmes.Result == 0 || busmes.Result == 2 || busmes.Result == 5 { //正向
				if newbus.Stations[0].PreStaDistance-busmes.BusDis >= config.IsMove { // 从出发站角度前进了至少3m
					newbus.Direction = 0
				} else if newbus.Stations[0].PreStaDistance-busmes.BusDis <= -config.IsMove { // 从出发站角度后退了了至少3m
					newbus.Direction = 1
				} else { //在原地不动
					if busmes.BusDirection[0] == 2 { //从初始站出发
						newbus.Direction = 0
					} else if busmes.BusDirection[0] == 3 { //从终点站出发
						newbus.Direction = 1
					} else if busmes.BusDirection[0] == 5 { // 初始方向不定
						newbus.Direction = 5
					} else {
						newbus.Direction = busmes.Result //继承方向
					}
				}
			} else { //反向
				if newbus.Stations[len(newbus.Stations)-1].PreStaDistance-busmes.BusDis >= config.IsMove { // 从出发站角度前进了至少5m
					newbus.Direction = 0
				} else if newbus.Stations[len(newbus.Stations)-1].PreStaDistance-busmes.BusDis <= -config.IsMove { // 从出发站角度后退了了至少5m
					newbus.Direction = 1
				} else {
					if busmes.BusDirection[0] == 2 { //从初始站出发
						newbus.Direction = 0
					} else if busmes.BusDirection[0] == 3 { //从终点站出发
						newbus.Direction = 1
					} else if busmes.BusDirection[0] == 5 { // 初始方向不定
						newbus.Direction = 5
					} else {
						newbus.Direction = busmes.Result //继承方向

					}
				}
			}

			if busmes.BusDirection[0] == 2 { //从初始站出发
				busmes.BusDirection = [4]int{0, 0, 0, 0}
				newbus.Direction = 0
			} else if busmes.BusDirection[0] == 3 { //从终点站出发
				busmes.BusDirection = [4]int{1, 1, 1, 1}
				newbus.Direction = 1
			} else if busmes.BusDirection[0] == 5 { // 初始方向不定
				busmes.BusDirection = [4]int{newbus.Direction, newbus.Direction, newbus.Direction, newbus.Direction}
			} else { //在路线中间
				//更新总和
				sum := busmes.BusDirection[0] + busmes.BusDirection[1] + busmes.BusDirection[2] + busmes.BusDirection[3] + newbus.Direction
				//更新四次路线方向
				busmes.BusDirection = [4]int{busmes.BusDirection[1], busmes.BusDirection[2], busmes.BusDirection[3], newbus.Direction}
				if sum <= 2 && busmes.Result == 1 { //总和小于等于2：00000/00001/00011
					newbus.Direction = 0
				} else if sum > 2 && busmes.Result == 0 { //总和大于2：00111，01111，11111
					newbus.Direction = 1
				} else {
					newbus.Direction = busmes.Result
				}
			}

		}
	}

	//更新 结果方向 与 距出发站距离
	if busmes.Result == 0 || busmes.Result == 2 || busmes.Result == 5 {
		busmes.BusDis = newbus.Stations[0].PreStaDistance
	} else {
		busmes.BusDis = newbus.Stations[len(newbus.Stations)-1].PreStaDistance
	}

	//将这一次的结果记录
	if (busmes.Result == 5) || ((newbus.Direction-busmes.Result)%2 == 0) { //求出的方向与开始时设置的方向相同
		busmes.Result = newbus.Direction
	} else {
		//求规约点与规约距离、规约路线段
		PreStationid, Lat1, Lon1, Distance := findStation(newbus.Lat, newbus.Lon, route, newbus.Direction)
		// 若规约距离过大，判断失效，更正判断方向
		if Distance > config.BusMinVertDis {
			newbus.Direction = busmes.Result
		} else {
			busmes.Result = newbus.Direction
			newbus.Stations = []Station{}
			//重新更新节点信息
			newbus.PreStationid = PreStationid
			newbus.Lat1 = Lat1
			newbus.Lon1 = Lon1
			newbus.Distance = Distance
			if newbus.Direction == 0 || newbus.Direction == 2 || newbus.Direction == 5 {
				newbus1 = route.Points
				for _, j := range route.Points {
					tem.PreStaDistance = j.PreStaDistance
					tem.LasStaDistance = j.LasStaDistance
					tem.Flag = j.Flag
					tem.Name = j.Name
					newbus.Stations = append(newbus.Stations, tem)
				}
			} else {
				newbus1 = route.OppositePoints
				for _, j := range route.OppositePoints {
					tem.PreStaDistance = j.PreStaDistance
					tem.LasStaDistance = j.LasStaDistance
					tem.Flag = j.Flag
					tem.Name = j.Name
					newbus.Stations = append(newbus.Stations, tem)
				}
			}
			//stanum1,stanum2 : 车的前面站数，后面站数  dis1,dis2:和前面一战、后面一站站距离
			stanum1, stanum2, dis1, dis2 = 0.0, 0.0, 0.0, 0.0
			flag = 0
			//更新每个节点信息
			//往后更新
			i = newbus.PreStationid + 1
			newbus.Stations[i].PreStaDistance = gps.GetDistance(newbus.Lat1, newbus.Lon1, newbus1[i].WGS84Lat, newbus1[i].WGS84lon)
			if newbus.Stations[i].Flag == 1 {
				stanum2 += 1
				dis2 = newbus.Stations[i].PreStaDistance
				flag = 1
			}
			newbus.Stations[i].StationNum = stanum2
			i++
			for ; i < len(newbus.Stations); i++ {
				newbus.Stations[i].PreStaDistance = newbus.Stations[i-1].PreStaDistance + newbus.Stations[i-1].LasStaDistance
				if newbus.Stations[i].Flag == 1 {
					stanum2 += 1
					if flag == 0 {
						dis2 = newbus.Stations[i].PreStaDistance
						flag = 1
					}
				}
				newbus.Stations[i].StationNum = stanum2
			}
			//往前更新
			flag = 0
			i = newbus.PreStationid
			newbus.Stations[i].PreStaDistance = gps.GetDistance(newbus.Lat1, newbus.Lon1, newbus1[i].WGS84Lat, newbus1[i].WGS84lon)
			if newbus.Stations[i].Flag == 1 {
				stanum1 += 1
				dis1 = newbus.Stations[i].PreStaDistance
				flag = 1
			}
			newbus.Stations[i].StationNum = stanum1
			i--
			for ; i >= 0; i-- {
				newbus.Stations[i].PreStaDistance = newbus.Stations[i+1].PreStaDistance + newbus.Stations[i].LasStaDistance
				if newbus.Stations[i].Flag == 1 {
					stanum1 += 1
					if flag == 0 {
						dis1 = newbus.Stations[i].PreStaDistance
						flag = 1
					}
				}
				newbus.Stations[i].StationNum = stanum1
			}
			//更新路程百分比
			newbus.Percent = (float64(stanum1)-1)/(float64(stanum1)+stanum2-1) + (float64(dis1)/(dis1+dis2))/(float64(stanum1)+stanum2-1)
			newbus.Percent *= 100
		}
	}

	return newbus, nil
}

//找出校车在所在路线上的上一个节点，返回值为：上一节点序列号，规约地点gps，规约距离
func findStation(lat, lon float64, route config.Route, flag int) (int, float64, float64, float64) {
	var minid int
	minid = 0
	var reslat, reslon, mindis float64
	mindis = 99999999.0
	var station []config.Station
	var temx, temy, temdis float64
	if flag == 0 || flag == 2 || flag == 5 {
		station = route.Points
	} else {
		station = route.OppositePoints
	}

	var x1, y1, x2, y2, x3, y3 float64
	x3, y3 = gps.MillierConvertion(lat, lon)
	x1, y1 = station[0].X, station[0].Y

	for i := 0; i < len(station)-1; i++ {
		//if math.Abs(lat-station[i+1].WGS84Lat)+math.Abs(lat-station[i].WGS84Lat) <= math.Abs(station[i+1].WGS84Lat-station[i].WGS84Lat)+0.0001 && math.Abs(lon-station[i+1].WGS84lon)+math.Abs(lon-station[i].WGS84lon) <= math.Abs(station[i+1].WGS84lon-station[i].WGS84lon)+0.0001 {
		x2, y2 = station[i+1].X, station[i+1].Y
		temx, temy = gps.GetFootOfPerpendicular(x1, y1, x2, y2, x3, y3) //求垂直点
		temx, temy = gps.MillierConvertion_1(temx, temy)                //垂直点xy坐标转->经纬度
		temdis = gps.GetDistance(lat, lon, temx, temy)                  //垂直点与校车位置的距离
		if temdis < mindis && (math.Abs(temx-station[i+1].WGS84Lat)+math.Abs(temx-station[i].WGS84Lat)) <= math.Abs(station[i+1].WGS84Lat-station[i].WGS84Lat)+config.LatDisOnLat && (math.Abs(temy-station[i+1].WGS84lon)+math.Abs(temy-station[i].WGS84lon)) <= math.Abs(station[i+1].WGS84lon-station[i].WGS84lon)+config.LonDisOnLon {
			mindis = temdis
			minid = i
			reslat = temx
			reslon = temy
			if mindis < config.IsInLine {
				break
			}
		}
		x1, y1 = x2, y2
	}
	return minid, reslat, reslon, mindis
}
